package modules

import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"
)

func EncodeResponse(w http.ResponseWriter, data interface{}, err string, statusCode int) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(statusCode)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"success": err == "",
		"message": err,
		"data":    data,
	})
}

// GetFileInfo 获取文件信息
func GetFileInfo(itemPath, rootName string) FileInfo {
	info, err := os.Stat(itemPath)
	if err != nil {
		log.Printf("获取文件信息失败，路径: %s，错误: %v", itemPath, err)
		return FileInfo{
			Name:         filepath.Base(itemPath),
			Type:         "unknown",
			Path:         "",
			ModifiedTime: "",
			Size:         0,
		}
	}
	itemType := "file"
	if info.IsDir() {
		itemType = "directory"
	}
	relPath, err := filepath.Rel(rootNames[rootName], itemPath)
	if err != nil {
		log.Printf("获取相对路径失败，路径: %s，错误: %v", itemPath, err)
		relPath = ""
	}
	relativePath := filepath.Join(rootName, relPath)
	modifiedTime := info.ModTime().Format(time.ANSIC)
	var fileSize int64
	if itemType == "file" {
		fileSize = info.Size()
	}
	return FileInfo{
		Name:         filepath.Base(itemPath),
		Type:         itemType,
		Path:         relativePath,
		ModifiedTime: modifiedTime,
		Size:         fileSize,
	}
}

// GetAssetContent 根据相对路径获取资源内容
func GetAssetContent(relativePath string) ([]byte, error) {
	// 从本地资源读取 （如果存在）
	localPath := filepath.Join(workDir, "assets/"+relativePath)
	if _, err := os.Stat(localPath); err == nil {
		content, err := os.ReadFile(localPath)
		if err != nil {
			log.Printf("从本地读取 %s 失败: %v", localPath, err)
		}
		return content, err
	} else if !os.IsNotExist(err) {
		// 处理除文件不存在之外的其他错误
		log.Printf("检查 %s 存在性时出错: %v", localPath, err)
	}

	// 尝试从嵌入资源中读取
	content, err := embedAssets.ReadFile("assets/" + relativePath)
	if err != nil {
		log.Printf("从嵌入资源中读取 %s 失败: %v", relativePath, err)
	}

	return content, err
}

// IsPathOutOfScope 检查路径是否越权
func IsPathOutOfScope(targetPath, rootName string, w http.ResponseWriter) bool {
	absTargetPath, _ := filepath.Abs(targetPath)
	absRootPath, _ := filepath.Abs(rootNames[rootName])
	if !strings.HasPrefix(absTargetPath, absRootPath) {
		log.Println("检测到路径越权尝试")
		if w == nil {
			EncodeResponse(w, nil, "路径越权", http.StatusBadRequest)
		}
		return true
	}
	return false
}

// CreateDirectory 创建目录
func CreateDirectory(path string, w http.ResponseWriter) bool {
	if err := os.MkdirAll(path, 0755); err != nil {
		log.Println("创建目录 %s 失败: %v", path, err)
		if w != nil {
			EncodeResponse(w, nil, "创建目录失败", http.StatusInternalServerError)
		}
		return false
	}
	return true
}

func IsPortInUse(port int) bool {
	addr := fmt.Sprintf(":%d", port)
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		return true
	}
	defer listener.Close()
	return false
}

func PrintRequestInfo(r *http.Request) {
	log.Printf("[%s] %s %s", r.RemoteAddr, r.Method, r.URL.String())
}

// IsFileAllowed 检查文件类型是否允许
func IsFileAllowed(filename string) bool {
	if len(config.AllowedExtensions) == 0 {
		// log.Printf("未配置允许的文件类型，默认允许所有文件")
		return true
	}
	ext := strings.ToLower(filepath.Ext(filename))
	if ext == "" {
		// log.Printf("文件 %s 没有扩展名，默认允许", filename)
		return false
	}
	ext = ext[1:]
	for _, allowedExt := range config.AllowedExtensions {
		if allowedExt == ext {
			// log.Printf("文件 %s 的扩展名 %s 允许", filename, ext)
			return true
		}
	}
	// log.Printf("文件 %s 的扩展名 %s 不允许", filename, ext)
	return false
}

// GetDirectoryItems 获取目录下的文件信息
func GetDirectoryItems(dirPath, rootName string) []FileInfo {
	var items []FileInfo
	files, err := os.ReadDir(dirPath)
	if err != nil {
		log.Printf("获取目录 %s 内容时出错: %v", dirPath, err)
		return items
	}
	for _, file := range files {
		itemPath := filepath.Join(dirPath, file.Name())
		itemInfo := GetFileInfo(itemPath, rootName)
		if itemInfo.Type == "file" && !IsFileAllowed(itemInfo.Name) {
			continue
		}
		items = append(items, itemInfo)
	}
	return items
}

// ListDirectories listDirectories 列出目录内容
func ListDirectories(w http.ResponseWriter, r *http.Request) {
	PrintRequestInfo(r)
	path := r.URL.Query().Get("path")
	path, _ = url.QueryUnescape(path)
	var data []FileInfo
	if path == "" {
		for _, rootDir := range config.RootDirs {
			dirName := filepath.Base(rootDir)
			itemInfo := GetFileInfo(rootDir, dirName)
			if itemInfo.Type == "file" && !IsFileAllowed(itemInfo.Name) {
				continue
			}
			data = append(data, itemInfo)
		}
		EncodeResponse(w, data, "", http.StatusOK)
		return
	}
	var targetPath, rootName string
	if _, exists := rootNames[path]; exists {
		targetPath = rootNames[path]
		rootName = path
	} else {
		parts := strings.SplitN(path, "/", 2)
		if len(parts) < 2 {
			log.Printf("指定路径 %s 格式不正确，应为 '根目录名/子路径'", path)
			EncodeResponse(w, nil, "路径格式错误", http.StatusBadRequest)
			return
		}
		rootName = parts[0]
		subPath := parts[1]
		if _, exists := rootNames[rootName]; !exists {
			log.Printf("指定的根目录名 %s 不存在", rootName)
			EncodeResponse(w, nil, "指定的目录不存在", http.StatusBadRequest)
			return
		}
		targetPath = filepath.Join(rootNames[rootName], subPath)
		info, err := os.Stat(targetPath)
		if err != nil || !info.IsDir() {
			log.Printf("指定路径 %s 不存在或非目录", targetPath)
			EncodeResponse(w, nil, "指定的目录不存在", http.StatusBadRequest)
			return
		}
	}
	if IsPathOutOfScope(targetPath, rootName, w) {
		return
	}
	items := GetDirectoryItems(targetPath, rootName)
	EncodeResponse(w, items, "", http.StatusOK)
}
